#include <stdio.h>
#include <stdlib.h>

void printMatrix(double Matrix[3][4]);
double* GaussianElimination(double Matrix[3][4]);

/*
 * 高斯消元法求解方程组
 * 参数一：存放方程组增广矩阵的二维数组的首地址
 * 参数二：增广矩阵的行数
 * 参数三：增广矩阵的列数
 * 返回值：方程组各未知量解所在数组
 */
double* GaussianEliminationGEN(double **Matrix,int row,int column);
void printMatrixGEN(double **Matrix,int line,int column);



int main() {

//    double Matrix01[3][4]={
//            {3,-4,1,11},
//            {15,-14,3,47},
//            {21,-40,15,97}
//    };
//    double Matrix02[6][7]={
//            {28,50,77,-69,-84,-65,-349},
//            {84,-100,-15,-31,-26,-5,-95},
//            {-25,30,-86,-34,-4,30,357},
//            {-21,7,-26,-86,-75,88,630},
//            {-85,95,-47,24,12,-66,-114},
//            {-57,-85,4,50,-11,54,340}
//    };
//    double Matrix03[3][4]={
//            {12,-3,3,15},
//            {-18,3,-1,-15},
//            {1,1,1,6}
//    };

    //矩阵输入程序
    int row,column;
    printf("please input the number of Xi:\n");
    scanf("%d",&row);   //获取行数
    column =row+1;  //自动定义增广矩阵的列数
    //创建增广矩阵空间
    double **Ma = (double **) malloc(sizeof(double *)*row);
    for (int i = 0; i < row; ++i) {
        Ma[i] = (double *) malloc(sizeof(double )*column);
    }
    //输入增广矩阵各行各列的值
    printf("please input the Matrix:\n");
    for (int i = 0; i < row; ++i) {
        for (int j = 0; j < column; ++j) {
            scanf("%lf",(*(Ma+i)+j));
        }
    }
    //获取各未知量所在数组
    double *Ans = GaussianEliminationGEN(Ma,row,column);
    for (int i = 0; i < row; ++i) {
        printf("X%d:%.4lf\t",i+1,Ans[i]);
    }

    //释放增广矩阵空间
    for (int i = 0; i < row; ++i)
        free(Ma[i]);
    free(Ma);
    free(Ans);

    //矩阵一：
//    double *Ans = GaussianElimination(Matrix01);
//    printf("\nx1 = %lf,x2 = %lf,x3 = %lf\n",Ans[0],Ans[1],Ans[2]);

    //方法二：
//    double *Ans2 = GaussianEliminationGEN(Matrix03);
//
//    for (int i = 0; i < 6; ++i) {
//        printf("Ans%d:%lf\t",i+1,Ans2[i]);
//    }

    return 0;
}



//普通高斯消元法通解
double* GaussianEliminationGEN(double **Matrix,int row,int column){
    double key,*Ans;  //Ans是用于存放最终答案的数组首地址，key是高斯消元消每列当前行的因子，即当前列当前行除以当前列的主元素的值
    Ans = malloc(sizeof(double )*row); //用于给答案存放开辟空间

    for (int i = 1; i <= column-2; ++i) {   //一共需要消除的列数
        for (int j = i+1; j <= row; ++j) {     //每一列需要消除的行数，j为目前所需要消除的行号

//            printMatrixGEN(Matrix,row,column);    //消除之前打印一下当前矩阵状况

            key=-Matrix[j-1][i-1]/Matrix[i-1][i-1]; //获取消除每行当前列的消除因子
            for (int k = 0; k < column; ++k)    //对当前行做变换
                Matrix[j-1][k]+=key*Matrix[i-1][k];
        }
    }
//    printMatrixGEN(Matrix,row,column);    //变换完成之后再次打印矩阵，查看当前矩阵状况

    for (int i = 0; i < row; ++i) {    //总共需要计算的答案数
        double sum=Matrix[row-1-i][column-1];  //回代答案被当前求的未知数的系数除之前总和的初值
        for (int j = row-1; j > row-1-i ; --j) {  //对每行答案回代并且右移，最终获取总和的终值
            sum-=Matrix[row-1-i][j]*Ans[j];
        }
        Ans[row-1-i]=sum/Matrix[row-1-i][row-1-i];   //获取当前所求未知数的值，即总和除以所求未知数系数
    }

    return Ans; //返回答案
}
//打印矩阵通解
void printMatrixGEN(double **Matrix,int line,int column){
    for (int i = 0; i < line; ++i) {
        for (int j = 0; j < column; ++j) {
            printf("%lf\t",*(*(Matrix+i)+j));
        }
        printf("\n");
    }

    printf("\n");
}

//高斯消元
double* GaussianElimination(double Matrix[3][4]){
    double key,*Ans;
    Ans = malloc(sizeof(double )*3);

    printMatrix(Matrix);

    key=-Matrix[1][0]/Matrix[0][0];  //获取对第一列第二行处理的key
    for (int i = 0; i < 4; ++i) {   //处理第一列第二行
        Matrix[1][i]+=key*Matrix[0][i];
    }

    printMatrix(Matrix);

    key=-Matrix[2][0]/Matrix[0][0];  //获取对第一列第三行处理的key
    for (int i = 0; i < 4; ++i) {   //处理第一列第三行
        Matrix[2][i]+=key*Matrix[0][i];
    }

    printMatrix(Matrix);

    key=-Matrix[2][1]/Matrix[1][1]; //获取对第二列第三行处理的key
    for (int i = 0; i < 4; ++i) {   //对第二列第三行处理
        Matrix[2][i]+=key*Matrix[1][i];
    }

    printMatrix(Matrix);

    Ans[2]=Matrix[2][3]/Matrix[2][2];
    Ans[1]=(Matrix[1][3]-Ans[2]*Matrix[1][2])/Matrix[1][1];
    Ans[0]=(Matrix[0][3]-Ans[2]*Matrix[0][2]-Ans[1]*Matrix[0][1])/Matrix[0][0];

    return Ans;
}
//打印矩阵
void printMatrix(double Matrix[3][4]){
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 4; ++j) {
            printf("%lf\t",Matrix[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}


